Clover icon

compiler

  1. Project Clover database Mon Jan 2 2023 15:09:37 MST
  2. Package com.google.javascript.jscomp

File InferJSDocInfo.java

 

Coverage histogram

../../../../img/srcFileCovDistChart9.png
54% of files have more coverage

Code metrics

40
56
6
1
224
121
43
0.77
9.33
6
7.17

Classes

Class Line # Actions
InferJSDocInfo 61 56 43 15
0.8529411685.3%
 

Contributing tests

This file is covered by 6048 tests. .

Source view

1    /*
2    * Copyright 2009 The Closure Compiler Authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10    * Unless required by applicable law or agreed to in writing, software
11    * distributed under the License is distributed on an "AS IS" BASIS,
12    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13    * See the License for the specific language governing permissions and
14    * limitations under the License.
15    */
16   
17    package com.google.javascript.jscomp;
18   
19    import com.google.common.base.Preconditions;
20    import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback;
21    import com.google.javascript.rhino.JSDocInfo;
22    import com.google.javascript.rhino.Node;
23    import com.google.javascript.rhino.Token;
24    import com.google.javascript.rhino.jstype.EnumType;
25    import com.google.javascript.rhino.jstype.JSType;
26    import com.google.javascript.rhino.jstype.ObjectType;
27   
28    import javax.annotation.Nullable;
29   
30    /**
31    * Set the JSDocInfo on all types.
32    *
33    * Propagates JSDoc across the type graph, but not across the symbol graph.
34    * This means that if you have:
35    * <code>
36    * var x = new Foo();
37    * x.bar;
38    * </code>
39    * then the JSType attached to x.bar may get associated JSDoc, but the
40    * Node and Var will not.
41    *
42    * JSDoc is initially attached to AST Nodes at parse time.
43    * There are 3 ways that JSDoc get propagated across the type system.
44    * 1) Nominal types (e.g., constructors) may contain JSDocInfo for their
45    * declaration.
46    * 2) Object types have a JSDocInfo slot for each property on that type.
47    * 3) Shape types (like structural functions) may have JSDocInfo.
48    *
49    * #1 and #2 should be self-explanatory, and non-controversial. #3 is
50    * a bit trickier. It means that if you have:
51    * <code>
52    * /** @param {number} x /
53    * Foo.prototype.bar = goog.abstractMethod;
54    * </code>
55    * the JSDocInfo will appear in two places in the type system: in the 'bar'
56    * slot of Foo.prototype, and on the function expression type created by
57    * this expression.
58    *
59    * @author nicksantos@google.com (Nick Santos)
60    */
 
61    class InferJSDocInfo extends AbstractPostOrderCallback
62    implements HotSwapCompilerPass {
63   
64    private final AbstractCompiler compiler;
65    @SuppressWarnings("unused")
66    private boolean inExterns;
67   
 
68  6643 toggle InferJSDocInfo(AbstractCompiler compiler) {
69  6643 this.compiler = compiler;
70    }
71   
 
72  12895 toggle @Override
73    public void process(Node externs, Node root) {
74  12895 if (externs != null) {
75  6288 inExterns = true;
76  6288 NodeTraversal.traverse(compiler, externs, this);
77    }
78  12895 if (root != null) {
79  6643 inExterns = false;
80  6643 NodeTraversal.traverse(compiler, root, this);
81    }
82    }
83   
 
84  0 toggle @Override
85    public void hotSwapScript(Node root, Node originalRoot) {
86  0 Preconditions.checkNotNull(root);
87  0 Preconditions.checkState(root.isScript());
88  0 inExterns = false;
89  0 NodeTraversal.traverse(compiler, root, this);
90    }
91   
 
92  674373 toggle @Override
93    public void visit(NodeTraversal t, Node n, Node parent) {
94  674373 JSDocInfo docInfo;
95   
96  674373 switch (n.getType()) {
97    // Infer JSDocInfo on types of all type declarations on variables.
98  175088 case Token.NAME:
99  175088 if (parent == null) {
100  0 return;
101    }
102   
103    // Only allow JSDoc on VARs, function declarations, and assigns.
104  175088 if (!parent.isVar() &&
105    !NodeUtil.isFunctionDeclaration(parent) &&
106    !(parent.isAssign() &&
107    n == parent.getFirstChild())) {
108  120371 return;
109    }
110   
111    // There are four places the doc info could live.
112    // 1) A FUNCTION node.
113    // /** ... */ function f() { ... }
114    // 2) An ASSIGN parent.
115    // /** ... */ x = function () { ... }
116    // 3) A NAME parent.
117    // var x, /** ... */ y = function() { ... }
118    // 4) A VAR gramps.
119    // /** ... */ var x = function() { ... }
120  54717 docInfo = n.getJSDocInfo();
121  54717 if (docInfo == null &&
122    !(parent.isVar() &&
123    !parent.hasOneChild())) {
124  54647 docInfo = parent.getJSDocInfo();
125    }
126   
127    // Try to find the type of the NAME.
128  54717 JSType varType = n.getJSType();
129  54717 if (varType == null && parent.isFunction()) {
130  0 varType = parent.getJSType();
131    }
132   
133    // If we have no type to attach JSDocInfo to, then there's nothing
134    // we can do.
135  54717 if (varType == null || docInfo == null) {
136  6085 return;
137    }
138   
139    // Dereference the type. If the result is not an object, or already
140    // has docs attached, then do nothing.
141  48632 ObjectType objType = dereferenceToObject(varType);
142  48632 if (objType == null || objType.getJSDocInfo() != null) {
143  11533 return;
144    }
145   
146  37099 attachJSDocInfoToNominalTypeOrShape(objType, docInfo, n.getString());
147  37099 break;
148   
149  99020 case Token.GETPROP:
150    // Infer JSDocInfo on properties.
151    // There are two ways to write doc comments on a property.
152    //
153    // 1)
154    // /** @deprecated */
155    // obj.prop = ...
156    //
157    // 2)
158    // /** @deprecated */
159    // obj.prop;
160  99020 if (parent.isExprResult() ||
161    (parent.isAssign() &&
162    parent.getFirstChild() == n)) {
163  50909 docInfo = n.getJSDocInfo();
164  50909 if (docInfo == null) {
165  19892 docInfo = parent.getJSDocInfo();
166    }
167  50909 if (docInfo != null) {
168  40776 ObjectType lhsType =
169    dereferenceToObject(n.getFirstChild().getJSType());
170  40776 if (lhsType != null) {
171    // Put the JSDoc in the property slot, if there is one.
172  40771 String propName = n.getLastChild().getString();
173  40771 if (lhsType.hasOwnProperty(propName)) {
174  40203 lhsType.setPropertyJSDocInfo(propName, docInfo);
175    }
176   
177    // Put the JSDoc in any constructors or function shapes as well.
178  40771 ObjectType propType =
179    dereferenceToObject(lhsType.getPropertyType(propName));
180  40771 if (propType != null) {
181  40746 attachJSDocInfoToNominalTypeOrShape(
182    propType, docInfo, n.getQualifiedName());
183    }
184    }
185    }
186    }
187  99020 break;
188    }
189    }
190   
191    /**
192    * Dereferences the given type to an object, or returns null.
193    */
 
194  130179 toggle private ObjectType dereferenceToObject(JSType type) {
195  130179 return ObjectType.cast(type == null ? null : type.dereference());
196    }
197   
198    /**
199    * Handle cases #1 and #3 in the class doc.
200    */
 
201  77845 toggle private void attachJSDocInfoToNominalTypeOrShape(
202    ObjectType objType, JSDocInfo docInfo, @Nullable String qName) {
203  77845 if (objType.isConstructor() ||
204    objType.isEnumType() ||
205    objType.isInterface()) {
206    // Named types.
207  48144 if (objType.hasReferenceName() &&
208    objType.getReferenceName().equals(qName)) {
209  32170 objType.setJSDocInfo(docInfo);
210   
211  32170 if (objType.isConstructor() || objType.isInterface()) {
212  32170 JSType.toMaybeFunctionType(objType).getInstanceType().setJSDocInfo(
213    docInfo);
214  0 } else if (objType instanceof EnumType) {
215  0 ((EnumType) objType).getElementsType().setJSDocInfo(docInfo);
216    }
217    }
218  29701 } else if (!objType.isNativeObjectType() &&
219    objType.isFunctionType()) {
220    // Structural functions.
221  12391 objType.setJSDocInfo(docInfo);
222    }
223    }
224    }